package com.bjpowernode.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.bjpowernode.core.PowernodeException;
import com.bjpowernode.entity.PmsCategory;
import com.bjpowernode.mapper.PmsCategoryMapper;
import com.bjpowernode.service.PmsCategoryService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 分类表 服务实现类
 * </p>
 *
 * @author zs
 * @since 2024-06-07
 */
@Service
public class PmsCategoryServiceImpl extends ServiceImpl<PmsCategoryMapper, PmsCategory> implements PmsCategoryService {
    @Resource
    PmsCategoryMapper pmsCategoryMapper;

    @Override
    //value相当于key的一部分（value+key）pms相当于前缀
    /*@Cacheable(value = "pms", key = "'category'")此注解的作用在于实现方法结果的缓存功能。具体说明如下：
      value = "pms"：指定了缓存的名称为"pms"，Spring会使用这个名字来查找或者创建一个对应的缓存管理器，用于存储和检索缓存数据。
      key = "'category'"：设定了缓存的键名为"category"。当此方法被调用时，会先检查缓存中是否存在键为"category"的条目，如果存在则直接返回缓存的结果，不再执行方法体内的逻辑；如果不存在，则执行方法体内逻辑，将返回的结果放入缓存中，键为"category"，以便后续相同条件的请求可以直接从缓存中获取数据，提高系统性能。*/
    //@Cacheable(value = "pms", key = "'category'")
    public List<PmsCategory> getAll() {
        //传递id空串目的是获取所有父分类（第一层级的）
        return this.getByParentId("");
    }

    //定义方法根据具体父节点id获取子分类
    private List<PmsCategory> getByParentId(String parentId) {
        QueryWrapper<PmsCategory> wrapper = new QueryWrapper<>();
        wrapper.eq("parent_id", parentId).orderByAsc("sort");
        //获取查到的结果分类并保存在list集合中
        List<PmsCategory> list = this.list(wrapper);
        //第一次传入空父节点id，查到的是所有第一层级的（因为第一层级是没有父节点id的），遍历时获取到此父节点的id进行递归查询，用此父节点的id查不到时代表没有子节点则跳出循环，反之有的话则继续递归查询，将查出来的子节点保存到父节点的children属性中，形成树状结构
        //此循环的实质是单独对父节点的子节点保存到父节点的children属性中，单独对每一个父节点进行操作将每一层的子阶点保存在父节点内，最终返回的是以父节点为主体的树状结构集合
        for (PmsCategory pmsCategory : list){
            //递归调用，查询获取第一层级下的子层级，并进行循环遍历
            List<PmsCategory> byParentId = this.getByParentId(pmsCategory.getId());
            pmsCategory.setChildren(byParentId);
        }
        return list;
    }
    @Override
    //@CacheEvict(value = "pms", key = "'category'")//此注解用于清除缓存，具体说明如下：当用户在前端页面进行了添加修改操作则要将数据同步到redis中，否则前端页面数据只会同步到数据库中，如果前端页面数据没有同步到redis中，则用户在页面上进行操作时，页面上的数据不会显示，而数据库中的数据会显示，造成数据不一致。
    public Boolean save(String name, String parentId, Integer level) {
        return this.save(new PmsCategory(name, parentId, level));
    }

    @Override
    //@CacheEvict(value = "pms", key = "'category'")
    public Boolean update(String id, String name) {
        return this.updateById(new PmsCategory(id,name));
    }

    //定义启用禁用方法1
    @Override
    //@CacheEvict(value = "pms", key = "'category'")
    public Boolean delete(String id, Boolean active) {
        //异常情况处理判断
        //禁用时看看下级有没有启用的分类（取得启用的子级的数量只要不为零其父级和其父级的父级都不能被禁用）
        //!active表示当前业务是需要被禁用的，表示当判断当前业务是禁用业务但是子级中有启用的，则抛出异常
        if (!active && this.getActiveChindreCount(id) > 0) {
            throw new PowernodeException("存在未禁用的下级，无法禁用当前分类");
        }

        //反之，启用时看看上级有没有禁用的分类
        //active表示当前业务是启用业务但是父级中有禁用的，则抛出异常
        if (active && !this.parentIsActive(id)) {
            throw new PowernodeException("存在未启用的上级，请先启用上级分类");
        }

        return this.updateById(new PmsCategory(id,active));
    }

    //定义启用禁用方法2（进行禁用启用状态改变的条件筛选）
    //禁用时看看下级有没有启用的分类（取得启用的子级的数量只要不为零其父级和其父级的父级都不能被禁用）
    private int getActiveChindreCount(String id) {
        QueryWrapper<PmsCategory> wrapper = new QueryWrapper<>();
        wrapper.eq("parent_id", id).eq("active", 1);
        return this.count(wrapper);
    }
    //反之，启用时看看上级有没有禁用的分类
    private Boolean parentIsActive(String id) {
        //取得父级id
        String parentId = this.getById(id).getParentId();
        //如果没有父级id则为第一层级返回true
        if(StringUtils.isBlank(parentId))
            return true;
        //如果有父级分类，将父级分类查询到
        PmsCategory parent = this.getById(parentId);
        //返回父级分类的启禁用状态
        return parent.getActive();
    }

    @Override//通过‘/’的形式进行查到的name的拼接
    public String getNameById(String[] categoryId) {
        List<String> list = new ArrayList<>();
        for (String categoryIdChild: categoryId) {
            String name = this.getById(categoryIdChild).getName();
            list.add(name);
        }
        return String.join("/", list);
    }
}
